package unit_test;

import static org.junit.Assert.*;

import gui.IUserInterface;
import gui.FakeConsole;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import logic.Parser;
import org.junit.Ignore;
import org.junit.Test;

//@author A0088498A
public class IntegrationTest {
	private final String TEST_CASE_DIRECTORY = "jUnit_resource/test%d/";
	private final String STORAGE_FILE = "task_record.txt";
	private final String OUTPUT_FILE = "output.txt";

	private File outputFile = new File(OUTPUT_FILE);
	private File expectedFile;

	private void resetOutputFile() throws IOException {
		FileOutputStream fos;
		fos = new FileOutputStream(STORAGE_FILE);
		fos.close();
	}

	private void retrieveExpectedResult(int testCaseId) {
		expectedFile = new File(String.format(TEST_CASE_DIRECTORY + OUTPUT_FILE, testCaseId));
	}

	/**
	 * Compare the contents of 2 File
	 * 
	 * @param file1
	 * @param file2
	 * @return true if 2 files have the same content. False if they are not or
	 *         Exceptions thrown when open the files
	 */
	private boolean contentEquals(File file1, File file2) {
		System.out.println("Comparing :" + file1 + " with " + file2);

		FileInputStream fis1, fis2;
		InputStreamReader isr1, isr2;
		BufferedReader br1, br2;
		try {
			fis1 = new FileInputStream(file1);
			fis2 = new FileInputStream(file2);
			isr1 = new InputStreamReader(fis1);
			isr2 = new InputStreamReader(fis2);
			br1 = new BufferedReader(isr1);
			br2 = new BufferedReader(isr2);

			String line1, line2;
			do {
				line1 = br1.readLine();
				line2 = br2.readLine();

				if (line1 == null || line2 == null) {
					break;
				}
			} while (line1.compareTo(line2) == 0);

			br1.close();
			br2.close();
			isr1.close();
			isr2.close();
			fis1.close();
			fis2.close();

			if (line1 == null && line2 == null) {
				System.out.println("Passed!");
				return true;
			} else {
				System.out.println("These lines are not the same: ");
				System.out.println(line1);
				System.out.println(line2);
				return false;
			}
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}

	@Test
	public void simpleAddTest() {
		try {
			int testId = 1;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name cs2103_final");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void multipleAddTest() {
		try {
			int testId = 2;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name final");
			parser.parseCommand("add -name cs2103_final");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void multipleAddTestDifferentType() {
		try {
			int testId = 3;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name final");
			parser.parseCommand("add -name cs2103_final -due 4.4.2014");
			parser.parseCommand("add -name cs2103_final -from 4.4.2014 -to 5.4.2014");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void duplicateAddTest() {
		try {
			int testId = 4;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name final");
			parser.parseCommand("add -name final");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void nonameAddTest() {
		try {
			int testId = 5;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add ");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void timedTaskWrongDateOrderAddTest() {
		try {
			int testId = 6;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name cs2103_final -from 5.4.2014 -to 4.4.2014");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void collideWithBlockAddTest() {
		try {
			int testId = 7;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("block -name block task -from 1.4.2014 -to 5.4.2014");
			parser.parseCommand("add -name task -from 2.4.2014 -to 7.4.2014");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	//@author A0097972J
	@Test
	public void timedTaskUsingRangeAddTest() {
		try {
			int testId = 8;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Workshop -from 5.4.14 -range 5");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void timedTaskMissingAddTest() {
		try {
			int testId = 9;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Workshop -from 5.4.2014");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void timedTaskUsingInvalidRangeAddTest() {
		try {
			int testId = 10;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Workshop -from 5.4.14 -range 5kk");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Ignore
	public void deadlineNextWeekAddTest() {
		try {
			int testId = 11;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Workshop -due next week");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void yearTooEarlyAddTest() {
		try {
			int testId = 12;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Workshop -due 1.1.11");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void yearTooLateAddTest() {
		try {
			int testId = 13;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Workshop -due 1.1.1324561");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void simpleDeleteTest() {
		try {
			int testId = 14;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Workshop");
			parser.parseCommand("delete -name Workshop");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void multiResultDeleteTest() {
		try {
			int testId = 15;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 1.4.14");
			parser.parseCommand("add -name Return report -due 5.4.14");
			parser.parseCommand("delete -name report");
			parser.parseCommand("confirm -id 1");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void noMatchDeleteTest() {
		try {
			int testId = 16;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 1.4.14");
			parser.parseCommand("delete -name workshop");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void noNameDeleteTest() {
		try {
			int testId = 17;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 1.4.14");
			parser.parseCommand("delete");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void simpleUpdateTest() {
		try {
			int testId = 18;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 1.4.14");
			parser.parseCommand("update -name Submit report");
			parser.parseCommand("confirm -id 1 -description to Sam -due 2.4.14");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void noNameUpdateTest() {
		try {
			int testId = 19;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 1.4.14");
			parser.parseCommand("update");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void fromOverdueToUndoneUpdateTest() {
		try {
			int testId = 20;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 5.4.14");
			parser.parseCommand("update -name Submit Report");
			parser.parseCommand("confirm -id 1 -due 5.4.16");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void simpleMarkTest() {
		try {
			int testId = 21;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 5.4.14");
			parser.parseCommand("mark -name Submit report");
			parser.parseCommand("confirm -id 1");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void noNameMarkTest() {
		try {
			int testId = 22;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 5.4.14");
			parser.parseCommand("mark");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void simpleUnmarkTest() {
		try {
			int testId = 23;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 5.4.14");
			parser.parseCommand("mark -name Submit report");
			parser.parseCommand("confirm -id 1");
			parser.parseCommand("unmark -name Submit report");
			parser.parseCommand("confirm -id 1");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void simpleSearchNameTest() {
		try {
			int testId = 24;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -description To Sam -due 5.4.14");
			parser.parseCommand("search -name report");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void endingSearchTest() {
		try {
			int testId = 25;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Send email -description To prof -due 11.4.14");
			parser.parseCommand("add -name Project meeting -description at Com1 -from 11.4.14 1000 -to 11.4.14 1200");
			parser.parseCommand("search -due 11.4.14");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void startingTimeSearchTest() {
		try {
			int testId = 26;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Attend workshop -description at Utown -from 9.4.14 -to 11.4.14");
			parser.parseCommand("search -startingTime 9.4.14");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void noIdConfirmTest() {
		try {
			int testId = 27;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 5.4.14");
			parser.parseCommand("mark -name Submit report");
			parser.parseCommand("confirm");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void wrongIdConfirmTest() {
		try {
			int testId = 28;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 5.4.14");
			parser.parseCommand("mark -name Submit report");
			parser.parseCommand("confirm -id abc");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void fromDeadlineToTimedTaskUpdateTest() {
		try {
			int testId = 29;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Submit report -due 5.4.14");
			parser.parseCommand("update  -name Submit report");
			parser.parseCommand("confirm -id 1 -name ProofRead -from 6.4.14 -to 8.4.14");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void fromTimedToDeadlineTaskUpdateTest() {
		try {
			int testId = 30;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name ProofRead report -from 6.4.14 -to 8.4.14");
			parser.parseCommand("update  -name ProofRead report");
			parser.parseCommand("confirm -id 1 -name Submit report -due 9.4.14 1700");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void showCorrectTaskStatusMarkAndUnmarkTest() {
		try {
			int testId = 31;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name Read report -from 6.4.14 -to 8.4.14"); // overdue
			parser.parseCommand("add -name Print report -due 12.4.14"); // overdue
			parser.parseCommand("add -name Find report -due 12.6.16"); // undone
			parser.parseCommand("mark -name report"); // show undone and overdue
			// only
			parser.parseCommand("confirm -id 1");
			parser.parseCommand("unmark -name report"); // show done only
			parser.parseCommand("confirm -id 1");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void unknowKeywordTest() {
		try {
			int testId = 32;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -anything taskname");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void noKeywordTest() {
		try {
			int testId = 33;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("-name taskname");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void thirtyFebDateTimeTest() {
		try {
			int testId = 34;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name test -due 30.2.14");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void zeroDateTimeTest() {
		try {
			int testId = 35;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name test -due 0.0.14");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void dashFormatDateTimeTest() {
		try {
			int testId = 36;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name test -due 1-4-14 2359");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void slashFormatDateTimeTest() {
		try {
			int testId = 37;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name test -due 1/4/14 1700");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void monthFormatDateTimeTest() {
		try {
			int testId = 38;
			System.out.println("\nSystem test case " + testId);
			resetOutputFile();
			retrieveExpectedResult(testId);

			IUserInterface ui = new FakeConsole(OUTPUT_FILE);
			Parser parser = new Parser(ui);
			parser.parseCommand("add -name test -due 1 apr 14 0900");

			assertTrue(contentEquals(expectedFile, outputFile));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}


}
